/*
 * Copyright (C) 2000-2008 Jens Nixdorf and various contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies of the Software, its documentation and marketing & publicity
 * materials, and acknowledgment shall be given in the documentation, materials
 * and software packages that this Software was used.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package org.mopore.jat.board;

import java.awt.AWTException;
import java.awt.BufferCapabilities;
import java.awt.Frame;
import java.awt.ImageCapabilities;

import javax.swing.JOptionPane;

public class StrategyChooser {

    // set of strategy-flags
    private static StrategySet optimalStrategy;

    // buffers should always be '2'
    private final static int numBuffers = 2;

    // milliseconds for acceptable maximum benchmark time
    // to let it be the optimized strategy
    private final static int acceptableTime = 100;

    // determine, if measured times should be displayed after
    // benchmarking (seems to be a problem to show them,
    // deactivated for now)
    private final static boolean showBenchmarkResults = false;

    // seems to be the most compatible default
    private static StrategySet currentlyFastestStrategy = new StrategySet(true, true, null);

    private static long currentlyFastestTime = 99999999;

    private static long timer = 0;

    /**
     * Quick loading of default strategy
     * 
     * @param frame
     * @return
     * @throws AWTException
     */
    public static Frame loadDefaultStrategy(Frame frame) throws AWTException {

        return applyStrategy(new StrategySet(true, true, null), frame);
    }

    /**
     * Starting point to get a saved strategy or bench a new strategy
     * 
     * @param frame
     *            The Frame to deal with
     * @return The Frame already prepared with the optimal strategy
     * @throws AWTException
     */
    public static Frame getOptimizedStrategy(Frame frame) throws AWTException {

        if (optimalStrategy == null) {
            optimalStrategy = benchmarkStrategies(frame, numBuffers, acceptableTime,
                    showBenchmarkResults);
        }

        return applyStrategy(optimalStrategy, frame);
    }

    /**
     * Benches all 16 possible strategies for the fastest
     * 
     * @param frame
     *            The Frame on which to test the settings
     * @return optimal set of strategy-flags
     * @throws AWTException
     */
    private static StrategySet benchmarkStrategies(Frame frame, int numBuffers, int acceptableTime,
            boolean showResults) throws AWTException {

        // !! this one is currently only testing agains the FlipCapability
        // variants
        // (assuming, that front & back capability is available)

        // TODO: iterate over the possible FlipContents
        StrategySet tryStrategy = new StrategySet(true, true, null, "default strategy");

        if (benchmarkStrategy(frame, tryStrategy) <= acceptableTime) {
            return tryStrategy;
        }

        if (showResults) {
            JOptionPane.showMessageDialog(null, "Needs " + currentlyFastestTime
                    + " Milliseconds\nStrategy name: " + optimalStrategy.toString(),
                    "mopore-togo benchmark", JOptionPane.OK_OPTION);
        }

        return currentlyFastestStrategy;
    }

    /**
     * Benches the given strategy, and returns it time
     * 
     * @return the time that was needed for applying.
     * @throws AWTException
     */
    private static long benchmarkStrategy(Frame frame, StrategySet tryStrategy) throws AWTException {
        Frame testFrame = frame;

        startClock();
        testFrame = applyStrategy(tryStrategy, testFrame);
        long time = stopClock();
        if (time < currentlyFastestTime) {
            currentlyFastestTime = time;
            currentlyFastestStrategy = tryStrategy;
        }
        return time;
    }

    /**
     * Starts the timer
     * 
     */
    private static void startClock() {
        timer = System.currentTimeMillis();
    }

    /**
     * Stopps the timer, and give back the measured duration
     * 
     * @return time in milliseconds since start
     */
    private static long stopClock() {
        return System.currentTimeMillis() - timer;
    }

    /**
     * Used to apply the strategy-flags to the Frame, and give it back
     * 
     * @param strategySet
     *            the strategy to apply
     * @param frame
     *            the frame where to apply the strategy
     * @return frame with created buffer strategy
     * @throws AWTException
     */
    private static Frame applyStrategy(StrategySet strategySet, Frame frame) throws AWTException {

        frame.createBufferStrategy(numBuffers, new BufferCapabilities(new ImageCapabilities(
                strategySet.isFrontCaps()), new ImageCapabilities(strategySet.isBackCaps()),
                strategySet.getFlipCaps()));
        return frame;
    }

    /**
     * Loads the strategy from whereever...
     * 
     * @param strategySet
     */
    public static void loadStrategy(StrategySet strategySet) {
        optimalStrategy = strategySet;
    }
}
